﻿using UnityEngine;
using System.Collections;
#if UNITY_EDITOR
using UnityEditor;
#endif
using System.Collections.Generic;
using System;
using System.IO;

public class CatchMouse : MonoBehaviour {
    const float maxCastDis = 1000;

    bool beginBrush = false;
    List<Vector3> onePath = new List<Vector3>();

    public int fromCityID = 0;
    public int toCityID = 0;
    public string cityNamePrefix = "city";
    public Transform FromCity = null;
    public Transform ToCity = null;
    public Transform CityRoot = null;

    [Serializable]
    class PathInfo
    {
        public List<Vector3> Path = new List<Vector3>();
        public int Index;
        public int FromID;
        public int EndID;
    }
    [Serializable]
    class CityLinkInfo
    {
        public int firstCityID;
        public int secondCityID;
        public int Index;
    }

    [SerializeField]
    List<CityLinkInfo> linkLst = new List<CityLinkInfo>();
    [SerializeField]
    List<PathInfo> pathLst = new List<PathInfo>();
    [SerializeField]
    public float sampleDis = 1f;

    public bool  CheckHasPath()
    {
        Predicate<CityLinkInfo> predicate = delegate (CityLinkInfo info)
        {
            if ((info.firstCityID == fromCityID && info.secondCityID == toCityID) ||
            (info.secondCityID == fromCityID && info.firstCityID == toCityID))
            {
                return true;
            }

            return false;
        };
        if (linkLst.FindIndex(predicate) > -1)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    public void DrawPath()
    {
        GameObject spawn = GetPathSpotRoot();
        if (spawn != null)
        {
            DestroyImmediate(spawn);
        }
        spawn = GetPathSpotRoot();

        for (int i = 0; i < pathLst.Count; i++)
        {
            PathInfo info = pathLst[i];

            for (int j = 0; j < info.Path.Count; j++)
            {
                GameObject prefab = Resources.Load("just_for_path/prefab_path_spot") as GameObject;
                GameObject spot = Instantiate(prefab);
                spot.transform.SetParent(spawn.transform);
                spot.transform.position = info.Path[j];
                spot.name = string.Format("path_{0}_{1}", i, j);
            }
        }
    }

    public void ClearPath()
    {
        if (fromCityID == 0 || toCityID == 0)
        {
            return;
        }

        Predicate<CityLinkInfo> predicate = delegate (CityLinkInfo info)
        {
            if ((info.firstCityID == fromCityID && info.secondCityID == toCityID) ||
            (info.secondCityID == fromCityID && info.firstCityID == toCityID))
            {
                return true;
            }

            return false;
        };

        int index = linkLst.FindIndex(predicate);
        if (index != -1)
        {
            CityLinkInfo info = linkLst[index];


            for (int i = 0; i < pathLst.Count; i++)
            {
                if (pathLst[i].Index == info.Index)
                {
                    pathLst.RemoveAt(i);
                    break;
                }
            }

            linkLst.RemoveAt(index);
        }
        CheckHasPath();
        DrawPath();
    }

    public void ClearAllPath()
    {
        linkLst.Clear();
        pathLst.Clear();
        onePath.Clear();
        CheckHasPath();
        DrawPath();
    }

    public void GenerateCityPath()
    {
        string path = Application.dataPath + "/../Log/";
        if (!Directory.Exists(path))
        {
            Directory.CreateDirectory(path);
        }

        string file_name = string.Format("{0}/{1}.txt", path,DateTime.Now.ToString("yyyy - MM - dd - HH - mm - ss"));
        StreamWriter swriter = new StreamWriter(file_name, true);

        Dictionary<int, List<string>> cityPathMap = new Dictionary<int, List<string>>();

        for (int i = 0; i < linkLst.Count; i++)
        {
            CityLinkInfo info = linkLst[i];
            PathInfo pathInfo = GetPathInfo(info.Index);

            int b1 = pathInfo.FromID == info.firstCityID ? 1 : 0;
            string str1 = string.Format("{0}|{1}|{2}", info.Index, pathInfo.FromID, pathInfo.EndID);
           
            if (cityPathMap.ContainsKey(info.firstCityID) == false)
            {
                cityPathMap.Add(info.firstCityID, new List<string>());
            }

            if (cityPathMap[info.firstCityID].Contains(str1) == false)
            {
                cityPathMap[info.firstCityID].Add(str1);
            }

            int b2 = pathInfo.FromID == info.secondCityID ? 1 : 0;
            string str2 = string.Format("{0}|{1}|{2}", info.Index, pathInfo.FromID,pathInfo.EndID);
            if (cityPathMap.ContainsKey(info.secondCityID) == false)
            {
                cityPathMap.Add(info.secondCityID, new List<string>());
            }

            if (cityPathMap[info.secondCityID].Contains(str2) == false)
            {
                cityPathMap[info.secondCityID].Add(str2);
            }
        }

        foreach (var item in cityPathMap)
        {           
            string str = string.Empty;
            for (int i = 0; i < item.Value.Count; i++)
            {
                if(i == item.Value.Count - 1)
                {
                    str += item.Value[i];
                }
                else
                {
                    str += item.Value[i] + ",";
                }
            }
            swriter.WriteLine(string.Format("城市id:{0}     {1}", item.Key, str));
        }

        for (int i = 0; i < pathLst.Count; i++)
        {
            string str = string.Empty;
            PathInfo info = pathLst[i];
            for (int j = 0; j < info.Path.Count; j++)
            {
                Vector3 pos = info.Path[j];
                string temp = string.Format("{0}|{1}|{2}",pos.x,pos.y,pos.z);
                if (j == info.Path.Count - 1)
                {
                    str += temp;
                }
                else
                {
                    str += temp + ",";
                }
            }

            swriter.WriteLine(string.Format("路径id:{0}     {1}", info.Index, str));
        }

        swriter.Close();

        swriter = null;
    }

    public void SaveData(GameObject pre = null)
    {
#if UNITY_EDITOR
        if (pre != null)
        {
            UnityEditor.PrefabUtility.ReplacePrefab(gameObject, pre,ReplacePrefabOptions.ConnectToPrefab);
        }
        else
        {
            var targetPrefab = UnityEditor.PrefabUtility.GetPrefabParent(gameObject) as GameObject;
            if (targetPrefab != null)
            {
                UnityEditor.PrefabUtility.ReplacePrefab(gameObject, targetPrefab, ReplacePrefabOptions.ConnectToPrefab);
            }
        }
        AssetDatabase.SaveAssets();
#endif
    }


    // Use this for initialization
    void Start () {
#if UNITY_EDITOR
        EditorApplication.playmodeStateChanged += OnPlayModeChange;
#endif
    }
	
	// Update is called once per frame
	void Update () {
        if (Input.GetMouseButtonDown(1))
        {
            beginBrush = true;
        }
        if (Input.GetMouseButtonUp(1))
        {
            beginBrush = false;
            SavePath();
        }

        if (beginBrush)
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            bool cast = Physics.Raycast(ray, out hit, maxCastDis, 1 << LayerMask.NameToLayer("terrain"));
            if (cast)
            {
                if (onePath.Count == 0)
                {
                    onePath.Add(hit.point);
                    //DrawOneSpot(hit.point);
                    DrawOneSpot(hit.point, onePath.Count);
                }
                else if (Vector3.Distance(onePath[onePath.Count - 1], hit.point) >= sampleDis)
                {
                    Debug.LogFormat(
                        "colliderName:{0},onePath.Pos:{1},hit.point:{2},sampleDis:{3},mouserPos:{4}",
                        hit.collider.name,
                        onePath[onePath.Count - 1],
                        hit.point,
                        sampleDis,
                        Input.mousePosition);
                    onePath.Add(hit.point);

                    DrawOneSpot(hit.point, onePath.Count);

                }
            }
        }

        //Debug.Log(Input.mousePosition.ToString());
    }

    private void DrawOneSpot(Vector3 pos, int count)
    {
        GameObject spawn = GetPathSpotRoot();

        GameObject prefab = Resources.Load("just_for_path/prefab_path_spot") as GameObject;
        GameObject spot = Instantiate(prefab);
        spot.transform.SetParent(spawn.transform);
        spot.transform.position = pos;
        spot.name = string.Format("single_spot_{0}", count);
    }

    private GameObject GetPathSpotRoot()
    {
        GameObject spawn = GameObject.FindGameObjectWithTag("Respawn");
        if (spawn == null)
        {
            spawn = new GameObject("path_spot_root");
            spawn.tag = "Respawn";
        }
        return spawn;
    }

    private void SavePath()
    {
        if (fromCityID == 0 || toCityID == 0)
        {
            return;
        }

        if (onePath.Count == 0)
        {
            return;
        }
        Transform city = GetCityTran(fromCityID);
        if (city == null)
        {
            return;
        }

        Predicate<CityLinkInfo> predicate = delegate (CityLinkInfo info)
        {
            if ((info.firstCityID == fromCityID && info.secondCityID == toCityID) ||
            (info.secondCityID == fromCityID && info.firstCityID == toCityID))
            {
                return true;
            }

            return false;
        };

        int index = linkLst.FindIndex(predicate);
        PathInfo pathInfo = null;
        if (index == -1)
        {
            pathInfo = new PathInfo();
            pathInfo.Path.AddRange(onePath);
            pathInfo.Index = pathLst.Count == 0 ? 0 : pathLst[pathLst.Count - 1].Index + 1;
            pathLst.Add(pathInfo);

            CityLinkInfo info = new CityLinkInfo();
            linkLst.Add(info);
            info.firstCityID = fromCityID;
            info.secondCityID = toCityID;
            info.Index = pathInfo.Index;
        }
        else
        {
            CityLinkInfo info = linkLst[index];

            pathInfo = GetPathInfo(info.Index);
            pathInfo.Path.Clear();
            pathInfo.Path.AddRange(onePath);
        }

        if (Vector3.Distance(onePath[0], city.position) <= Vector3.Distance(onePath[onePath.Count - 1], city.position))
        {
            pathInfo.FromID = fromCityID;
            pathInfo.EndID = toCityID;
        }
        else
        {
            pathInfo.FromID = toCityID;
            pathInfo.EndID = fromCityID;
        }

        DrawPath();
        onePath.Clear();
        CheckHasPath();
    }

    private Transform GetCityTran(int cityID)
    {

        string cityName = string.Format("{0}{1}", cityNamePrefix, cityID);
        if (CityRoot != null)
        {
            Transform city = CityRoot.Find(cityName);
            return city;
        }

        return null;
    }

    private PathInfo GetPathInfo(int index)
    {
        for (int i = 0; i < pathLst.Count; i++)
        {
            if (pathLst[i].Index == index)
            {
                return pathLst[i];
            }
        }

        return null;
    }

    private void OnPlayModeChange()
    {
        //Debug.Log("isPlaying1" + Application.isPlaying);
        //Debug.Log("isPlaying2" + EditorApplication.isPlaying);
        //Debug.Log("willchange" + EditorApplication.isPlayingOrWillChangePlaymode);
#if UNITY_EDITOR
        if (EditorApplication.isPlayingOrWillChangePlaymode == false &&
            EditorApplication.isPlaying == true)
        {
            SaveData();
        }
#endif
    }
}
